package de.se.ludoapp.gaming;

import java.util.ArrayList;
import java.util.List;

import org.ksoap2.HeaderProperty;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.util.Log;
import de.se.ludoapp.response.GameFieldResponse;
import de.se.ludoapp.response.GameListResponse;
import de.se.ludoapp.response.GameResponse;
import de.se.ludoapp.response.HighscoreResponse;
import de.se.ludoapp.response.PlayerDiceResponse;
import de.se.ludoapp.response.RequestingPlayerListResponse;
import de.se.ludoapp.response.ReturncodeResponse;
import de.se.ludoapp.response.UserLoginResponse;

//TODO Kommentare anpassen, da die auch von Th�ne kopiert wurden

/**
 * This class is used for communication with the server. The SessionId isn´t
 * here saved because this class is created again and again. SessionId
 * integrated into users. You get with the LudoApplication the user and
 * therefore its SessionId.
 * 
 * @author Felix, Marlen
 * 
 */
public class LudoSystemStub implements LudoSystem {

	/**
	 * Namespace is the targetNamespace in the WSDL.
	 */
	private static final String NAMESPACE = "http://gaming.ludo.de/";

	/**
	 * The WSDL URL. Its value is the location attribute of the soap:address
	 * element for a port element in a WSDL. Unless the web service is also
	 * hosted on the Android device, the hostname should not be specified as
	 * localhost, because the application runs on the Android device while the
	 * web service is hosted on the localhost server. Specify hostname as the IP
	 * address of the server hosting the web service (or "10.0.2.2 instead of
	 * 'localhost' when running in the emulator).
	 */
	// URL für Handynetz
	private static final String URL = "http://192.168.173.1:8080/LudoEJB/LudoOnlineIntegrationImpl";
	// URL für Emulator
	// private static final String URL =
	// "http://10.0.2.2:8080/LudoEJB/LudoOnlineIntegrationImpl";

	/**
	 * TAG contains the class name and is used for logging.
	 */
	private static final String TAG = LudoSystemStub.class.getName();

	@Override
	public UserLoginResponse login(String username, String password) {
		Log.d(TAG, "login called.");
		String METHOD_NAME = "login";
		SoapObject response = executeSoapAction(METHOD_NAME, username, password);
		Log.d(TAG, "login Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);

		SoapObject userTo = (SoapObject) response.getProperty("user");

		int sessionId = Integer.parseInt(userTo
				.getPrimitivePropertySafelyAsString("sessionId"));
		String userName = userTo.getPrimitivePropertySafelyAsString("userName");

		return new UserLoginResponse(returnCode, message, sessionId, userName);
	}

	@Override
	public GameListResponse getFreeGames() {
		Log.d(TAG, "getFreeGames called.");
		String METHOD_NAME = "getFreeGames";
		SoapObject response = executeSoapAction(METHOD_NAME);
		Log.d(TAG, response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);

		ArrayList<Game> gamelist = new ArrayList<Game>();
		for (int i = 2; i < response.getPropertyCount(); i++) {
			SoapObject gameTo = (SoapObject) response.getProperty(i);
			Game game = getGameTo(gameTo);
			gamelist.add(game);
		}
		return new GameListResponse(returnCode, message, gamelist);
	}

	@Override
	public GameListResponse getRunningGames() {
		Log.d(TAG, "getRunningGames called.");
		String METHOD_NAME = "getRunningGames";
		SoapObject response = executeSoapAction(METHOD_NAME);
		Log.d(TAG, response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		ArrayList<Game> runningGameList = new ArrayList<Game>();
		for (int i = 2; i < response.getPropertyCount(); i++) {
			SoapObject gameTO = (SoapObject) response.getProperty(i);
			Game g = getGameTo(gameTO);
			runningGameList.add(g);
		}
		return new GameListResponse(returnCode, message, runningGameList);
	}

	@Override
	public GameResponse openNewGame(int sessionId) {
		Log.d(TAG, "openNewGame called.");
		String METHOD_NAME = "openNewGame";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId);
		Log.d(TAG, "Open NewGame Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		SoapObject gameTo = (SoapObject) response.getProperty("game");
		Game game = getGameTo(gameTo);

		return new GameResponse(returnCode, message, game);
	}

	@Override
	public void logout(User user) {
		Log.d(TAG, "logout called.");
		String METHOD_NAME = "logout";
		SoapObject response = executeSoapAction(METHOD_NAME,
				user.getSessionId());
		Log.d(TAG, response.toString());
	}

	@Override
	public void closeGame(Game game) {
		Log.d(TAG, "closeGame called.");
		String METHOD_NAME = "closeGame";
		SoapObject response = executeSoapAction(METHOD_NAME, game.getGameId());
		Log.d(TAG, response.toString());
	}

	public RequestingPlayerListResponse handleRequests(int sessionId, int gameId) {
		Log.d(TAG, "hadleRequests called.");
		String METHOD_NAME = "handleRequests";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG, "handleRequests Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);

		ArrayList<String> playerlist = new ArrayList<String>();
		for (int i = 3; i < response.getPropertyCount(); i++) {
			String playerName = response.getPropertyAsString(i);
			Log.d(TAG, playerName);
			playerlist.add(playerName);
		}

		return new RequestingPlayerListResponse(returnCode, message,
				playerlist, gameId);
	}

	@Override
	public HighscoreResponse getHighscore(String gameName) {
		Log.d(TAG, "getHighscoreResponse called");
		String METHOD_NAME = "getHighscoreList";
		SoapObject r = executeSoapAction(METHOD_NAME, gameName);
		Log.d(TAG, "highscore Response: " + r.toString());
		int returnCode = getResponseReturnCode(r);
		String message = getResponseMessage(r);

		ArrayList<String> highscoreList = new ArrayList<String>();
		for (int i = 2; i < r.getPropertyCount(); i++) {
			String highscore = r.getPropertyAsString(i);
			Log.d(TAG, highscore);
			highscoreList.add(highscore);
		}
		return new HighscoreResponse(returnCode, message, highscoreList);
	}

	public GameResponse allowUserToEnterTheGame(int sessionId, String userName,
			int gameId) {
		Log.d(TAG, "allowUserToEnterTheGame called.");
		String METHOD_NAME = "allowUserToEnterTheGame";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId,
				userName, gameId);
		Log.d(TAG, "allowUserToEnterTheGame Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		SoapObject gameTo = (SoapObject) response.getProperty("game");
		Game game = getGameTo(gameTo);

		return new GameResponse(returnCode, message, game);
	}

	public GameResponse getGameById(int gameId) {
		Log.d(TAG, "getGameById called.");
		String METHOD_NAME = "getGameById";
		SoapObject response = executeSoapAction(METHOD_NAME, gameId);
		Log.d(TAG, "getGameById Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		SoapObject gameTo = (SoapObject) response.getProperty("game");
		Game game = getGameTo(gameTo);

		return new GameResponse(returnCode, message, game);
	}

	public ReturncodeResponse enterExistingGame(int sessionId, int gameId) {
		Log.d(TAG, "enterExistingGame called.");
		String METHOD_NAME = "enterExistingGame";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG, "enterExistingGame Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		// TODO am Server Response umstellen
		return new ReturncodeResponse(returnCode, message);

	}

	@Override
	public ReturncodeResponse leaveRunningGame(int sessionId, int gameId) {
		Log.d(TAG, "leaveRunningGame called.");
		String METHOD_NAME = "leaveRunningGame";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG, "leaveRunningGame Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		return new ReturncodeResponse(returnCode, message);
	}

	public ReturncodeResponse leaveOpenGame(int sessionId, int gameId) {
		Log.d(TAG, "leaveOpenGame called.");
		String METHOD_NAME = "leaveOpenGame";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG, "leaveOpenGame Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		return new ReturncodeResponse(returnCode, message);
	}

	public GameResponse isTheRequestingPlayerAccepted(int sessionId, int gameId) {
		Log.d(TAG, "isTheRequestingPlayerAccepted called.");
		String METHOD_NAME = "isTheRequestingPlayerAccepted";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG,
				"isTheRequestingPlayerAccepted Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		Game game = null;
		if (returnCode == 0) {
			SoapObject gameTo = (SoapObject) response.getProperty("game");
			game = getGameTo(gameTo);
		}
		return new GameResponse(returnCode, message, game);
	}

	public ReturncodeResponse removeRequestingPlayerForGame(int sessionId,
			int gameId) {
		Log.d(TAG, "removeRequestingPlayerForGame called.");
		String METHOD_NAME = "removeRequestingPlayerFromList";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG,
				"removeRequestingPlayerForGame Response:" + response.toString());
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		return new ReturncodeResponse(returnCode, message);

	}

	public GameFieldResponse startGame(int sessionId, int gameId) {
		Log.d(TAG, "startGame called.");
		String METHOD_NAME = "startGame";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG, "startGame Response:" + response.toString());

		GameFieldResponse gfr = getGameFieldResponse(response, gameId);
		gameFieldasString(gfr.getGameField());
		return gfr;
	}

	@Override
	public UserLoginResponse register(String username, String password) {
		Log.d(TAG, "register executed.");
		String METHOD_NAME = "register";

		Log.d(TAG, "username: " + username);

		SoapObject response = executeSoapAction(METHOD_NAME, username, password);
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		Log.d(TAG, response.toString());
		SoapObject userTo = (SoapObject) response.getProperty("user");

		int sessionId = Integer.parseInt(userTo
				.getPrimitivePropertySafelyAsString("sessionId"));
		String userName = userTo.getPrimitivePropertySafelyAsString("userName");

		return new UserLoginResponse(returnCode, message, sessionId, userName);

	}

	@Override
	public PlayerDiceResponse dice(int sessionId, int gameId) {
		Log.d(TAG, "dice executed.");
		String METHOD_NAME = "dice";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG, "dice Response:" + response.toString());

		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		int diceResult = Integer.parseInt(response
				.getPrimitivePropertySafelyAsString("diceResult"));
		ArrayList<Integer> possibleCharacters = new ArrayList<Integer>();
		// 3-x
		for (int i = 3; i < response.getPropertyCount(); i++) {
			Integer possibleCharacter = Integer.parseInt(response
					.getPropertyAsString(i));
			Log.d(TAG, "PossibleCharacter:" + String.valueOf(possibleCharacter));
			possibleCharacters.add(possibleCharacter);
		}
		return new PlayerDiceResponse(returnCode, message, diceResult,
				possibleCharacters);
	}

	public GameFieldResponse askForUpdatesOnGameField(int gameId,
			int[] gameField) {
		Log.d(TAG, "askForUpdatesOnGameField called.");
		String METHOD_NAME = "askForUpdatesOnGameField";
		SoapObject response = executeSoapAction(METHOD_NAME, gameId,
				gameField[0], gameField[1], gameField[2], gameField[3],
				gameField[4], gameField[5], gameField[6], gameField[7],
				gameField[8], gameField[9], gameField[10], gameField[11],
				gameField[12], gameField[13], gameField[14], gameField[15]);
		Log.d(TAG, "askForUpdatesOnGameField Response:" + response.toString());

		GameFieldResponse gfr = getGameFieldResponse(response, gameId);
		gameFieldasString(gfr.getGameField());
		return gfr;
	}

	public GameFieldResponse moveCharacter(int gameId, int sessionId,
			int gameFieldIndex, int diceResult) {
		Log.d(TAG, "moveCharacter called.");
		Log.d(TAG, "gameId:" + gameId);
		Log.d(TAG, "gameFieldIndex:" + gameFieldIndex);
		Log.d(TAG, "session:" + sessionId);
		Log.d(TAG, "diceresult:" + diceResult);
		String METHOD_NAME = "moveCharacter";
		SoapObject response = executeSoapAction(METHOD_NAME, gameId, sessionId,
				gameFieldIndex, diceResult);
		Log.d(TAG, "moveCharacter Response:" + response.toString());
		GameFieldResponse gfr = getGameFieldResponse(response, gameId);
		gameFieldasString(gfr.getGameField());
		return gfr;
	}

	public GameFieldResponse isTheGameStarted(int sessionId, int gameId) {
		Log.d(TAG, "isTheGameStarted called.");
		String METHOD_NAME = "isTheGameStarted";
		SoapObject response = executeSoapAction(METHOD_NAME, sessionId, gameId);
		Log.d(TAG, "isTheGameStarted Response:" + response.toString());
		// TODO Response ohe gameField auslesen wenn returncode nicht 1 ist
		GameFieldResponse gfr = getGameFieldResponse(response, gameId);
		gameFieldasString(gfr.getGameField());
		return gfr;
	}

	public void gameFieldasString(ArrayList<Integer> gameField) {
		String gamefieldString = "gameField [ ";
		if (gameField != null) {
			for (Integer i : gameField) {
				gamefieldString += i + ", ";
			}
			gamefieldString += "]";
			Log.d(TAG, gamefieldString);
		}
	}

	private int getResponseReturnCode(SoapObject response) {
		return Integer.parseInt(response
				.getPrimitivePropertySafelyAsString("returnCode"));
	}

	private String getResponseMessage(SoapObject response) {
		return response.getPrimitivePropertySafelyAsString("msg");
	}

	private Game getGameTo(SoapObject gameTo) {
		int gameId = Integer.parseInt(gameTo
				.getPrimitivePropertySafelyAsString("gameId"));
		String gameStatus = gameTo
				.getPrimitivePropertySafelyAsString("gameStatus");
		String nameYellowPlayer = gameTo
				.getPrimitivePropertySafelyAsString("nameYellowPlayer");
		String nameRedPlayer = gameTo
				.getPrimitivePropertySafelyAsString("nameRedPlayer");
		String nameGreenPlayer = gameTo
				.getPrimitivePropertySafelyAsString("nameGreenPlayer");
		String nameBluePlayer = gameTo
				.getPrimitivePropertySafelyAsString("nameBluePlayer");
		Game g = new Game(gameId, gameStatus, nameYellowPlayer, nameRedPlayer,
				nameGreenPlayer, nameBluePlayer);
		return g;
	}

	private GameFieldResponse getGameFieldResponse(SoapObject response,
			int gameId) {
		int returnCode = getResponseReturnCode(response);
		String message = getResponseMessage(response);
		boolean updates = false;
		boolean artificialOpponentPlayer = false;
		ArrayList<Integer> gameField = null;
		int upNext = 0;
		String playerYellow = response
				.getPrimitivePropertySafelyAsString("nameYellowPlayer");
		String playerRed = response
				.getPrimitivePropertySafelyAsString("nameRedPlayer");
		String playerGreen = response
				.getPrimitivePropertySafelyAsString("nameGreenPlayer");
		String playerBlue = response
				.getPrimitivePropertySafelyAsString("nameBluePlayer");
		if (returnCode == 0) {
			updates = Boolean.parseBoolean(response
					.getPrimitivePropertySafelyAsString("updates"));
			upNext = Integer.parseInt(response
					.getPrimitivePropertySafelyAsString("upNext"));
			artificialOpponentPlayer = Boolean
					.parseBoolean(response
							.getPrimitivePropertySafelyAsString("artificialOpponentPlayer"));
			SoapObject gameFieldTO = (SoapObject) response
					.getProperty("gameFieldTO");
			gameField = new ArrayList<Integer>();
			for (int i = 0; i < gameFieldTO.getPropertyCount(); i++) {
				Integer character = Integer.parseInt(gameFieldTO
						.getPropertyAsString(i));
				gameField.add(character);
			}
		}
		return new GameFieldResponse(returnCode, message, updates, upNext,
				gameId, gameField, artificialOpponentPlayer, playerYellow,
				playerRed, playerGreen, playerBlue);
	}

	/**
	 * This method delegates a invocation to a stored WebService.
	 * 
	 * @param methodName
	 * @return
	 */
	private SoapObject executeSoapAction(String methodName, Object... args) {

		Object result = null;

		/*
		 * Create a org.ksoap2.serialization.SoapObject object to build a SOAP
		 * request. Specify the namespace of the SOAP object and method name to
		 * be invoked in the SoapObject constructor.
		 */
		SoapObject request = new SoapObject(NAMESPACE, methodName);

		/*
		 * The array of arguments is copied into properties of the SOAP request
		 * using the addProperty method.
		 */
		for (int i = 0; i < args.length; i++) {
			request.addProperty("arg" + i, args[i]);
		}

		/*
		 * Next create a SOAP envelop. Use the SoapSerializationEnvelope class,
		 * which extends the SoapEnvelop class, with support for SOAP
		 * Serialization format, which represents the structure of a SOAP
		 * serialized message. The main advantage of SOAP serialization is
		 * portability. The constant SoapEnvelope.VER11 indicates SOAP Version
		 * 1.1, which is default for a JAX-WS webservice endpoint under JBoss.
		 */
		SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
				SoapEnvelope.VER11);

		/*
		 * Assign the SoapObject request object to the envelop as the outbound
		 * message for the SOAP method call.
		 */
		envelope.setOutputSoapObject(request);

		/*
		 * Create a org.ksoap2.transport.HttpTransportSE object that represents
		 * a J2SE based HttpTransport layer. HttpTransportSE extends the
		 * org.ksoap2.transport.Transport class, which encapsulates the
		 * serialization and deserialization of SOAP messages.
		 */
		HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

		try {
			/* Make the soap call using the SOAP_ACTION and the soap envelop. */
			List<HeaderProperty> reqHeaders = null;
			@SuppressWarnings({ "unused", "unchecked" })
			List<HeaderProperty> respHeaders = androidHttpTransport.call(
					NAMESPACE + methodName, envelope, reqHeaders);

			/*
			 * Get the web service response using the getResponse method of the
			 * SoapSerializationEnvelope object. The result has to be cast to
			 * SoapPrimitive, the class used to encapsulate primitive types, or
			 * to SoapObject.
			 */
			result = envelope.getResponse();

			if (result instanceof SoapFault) {
				throw (SoapFault) result;
			}
		} catch (SoapFault e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return (SoapObject) result;
	}

}